'''
Created on 12/12/2011

@author: Leo
'''
from page import Page

class Paging:
    '''
    classdocs
    '''


    def __init__(self, memory, pageSize, disc):
        '''
        Constructor
        '''
        
        self.memory = memory
        self.programTable = {} # tiene la relacion pid / pageTable de cada proceso
        self.marcosMemoria = {} #marcos que representan a la memoria (?)
        self.pageSize = pageSize #tamanio de pagina
        self.marcosLibres = []
        self.disc = disc
        self.contadorDeReemplazo = 0
        self.pages = []
        self.mapMemory()
        self.scheduler = None
    def mapMemory(self):
        '''
        Crea la lista de marcos, con las direcciones de memoria fisica, y crea la lo lista de marcos libres
        '''
        cantPaginas = self.memory.getSize() // self.pageSize #cantidad de paginas que entran en la memoria
        direccionFisica = 0
        tempPageSize = self.pageSize
        numeroDeMarco=0
        
        while cantPaginas>0:
            marco = []
            while tempPageSize>0:
                marco.append(direccionFisica) 
                direccionFisica+=1
                tempPageSize-=1
            self.marcosMemoria[numeroDeMarco] = marco
            tempPageSize = self.pageSize
            cantPaginas-=1
            numeroDeMarco+=1
        
        print "[paging] marcos generados: %s"% (self.marcosMemoria)    
        for marco in self.marcosMemoria:
         
            self.marcosLibres.append(marco)
            
     
            
    def load(self,mmu, program, pid):
        print "[mmu]cargando %s"%(program)
        resto = program.programSize % self.pageSize
        cantPaginas = program.programSize // self.pageSize #son la cantidad de paginas para asignar a un programa
        if resto is not 0:
            cantPaginas+=1
        
        pageTable = {}    
        contadorPagina = 0
        while cantPaginas > 0:
           
            pagina = Page(program.name, self.pageSize, self.disc, contadorPagina)
            pageTable[contadorPagina] = pagina
            
            if not self.marcosLibres==[]:
                
                self.completeLoad(pagina)

            contadorPagina+=1
            cantPaginas-=1
        self.programTable[pid] = pageTable   
        
    
    def cargarPaginas(self,mmu, program, pid):
        
        #print "cargando %s"%(program)
        resto = program.programSize % self.pageSize
        cantPaginas = program.programSize // self.pageSize #son la cantidad de paginas para asignar a un programa
        if resto is not 0:
            cantPaginas+=1
        
        pageTable = {}    
        contadorPagina = 0
        while cantPaginas > 0:
           
            pagina = Page(program.name, self.pageSize, self.disc, contadorPagina)
            pageTable[contadorPagina] = pagina
            
            if not self.marcosLibres==[]:
                
                self.completeLoad(pagina)
            
            contadorPagina+=1
            cantPaginas-=1
        self.programTable[pid] = pageTable 
        
        
    def completeLoad(self, page):
        
        
       
        page.marco = self.marcosLibres.pop(0)
        i=0
        marco = self.marcosMemoria[page.marco]
        instrucciones= page.readPageFromDisc()
        size = page.pageSize
        
         
        for instruccion in instrucciones:  
            
            print "[mmu]sobreescribiendo marco: %s desplazamiento: %d"%(page.marco,i)
            self.memory.load(marco[i], instruccion)
            i+=1
            size -=1
        
        while size > 0:
            self.memory.load(marco[i], "fragmentacion interna") 
            size -=1
            
        page.estaEnMemoria = True
        self.pages.append(page)
        
        
        
    def read(self ,mmu, pid, pc):
        
        numeroDePagina=pc//self.pageSize
        
        
        tablaDePaginas=self.programTable[pid]
        
        page = tablaDePaginas[numeroDePagina]
        
        #page.used = self.contadorDeReemplazo
        
        if not page.estaEnMemoria :
            print "[mmu]fallo de pagina"
            self.contextSwitch(page)
        page.used = self.contadorDeReemplazo
        marco = self.marcosMemoria[page.marco]
        dirFisica = marco[(pc % self.pageSize)-2]
        
        self.contadorDeReemplazo +=1
        return self.memory.read(dirFisica)
        
        
        
        
    def unload(self,mmu, pid):
        pageTable=self.programTable[pid]
        cantPaginas = len(pageTable)
        contador=0
        while contador < cantPaginas:
            page=pageTable[contador]
            
            if  page.estaEnMemoria :
                self.completeUnload(page)#agregado
                self.marcosLibres.append(page.marco)
                page.estaEnMemoria = False
                self.pages.remove(page)
            contador+=1
           
            
    def contextSwitch(self, page):
        
        self.swap()
        self.completeLoad(page)

        
    def swap(self):
        
        paginaAReemplazar = self.algoritmoDeReemplazo()
        if paginaAReemplazar is not None:
        #paginaAReemplazar.savePageToDisc
            self.marcosLibres.append(paginaAReemplazar.marco)
            paginaAReemplazar.estaEnMemoria = False
        
            self.completeUnload(paginaAReemplazar)
        
            self.pages.remove(paginaAReemplazar)
        
        
    def completeUnload(self, page):
        
        
        direcciones = self.marcosMemoria[page.marco]
        
        
        for d in direcciones:
            
            self.memory.unload(d)
        
        
    def processInRAM(self, pid):
        return True
          
        
    
    def algoritmoDeReemplazo(self):
        self.pages=sorted(self.pages, key=lambda page:page.used)
        if not len(self.pages) == 0:
            return self.pages[0]
        
        
        
        
    
        
        
    